﻿using System;
using System.Collections.Specialized;
using Microsoft.SharePoint;
using System.Security.Principal;
using Evolution.Utilities;

namespace Evolution.Security
{
    [Serializable]
    public class SecurityEntity
    {
        #region Fields

        private StringCollection _users;            // AD User accounts
        private StringCollection _securityGroups;   // AD Group accounts
        private StringCollection _spGroups;         // SharePoint Groups

        public static readonly SecurityEntity Empty = new SecurityEntity(String.Empty, String.Empty, String.Empty);

        #endregion

        #region Constructors

        public SecurityEntity()
        {
            this._users = new StringCollection();
            this._securityGroups = new StringCollection();
            this._spGroups = new StringCollection();
        }

        public SecurityEntity(string users, string securityGroups, string spGroups)
            : this()
        {
            if(!StringUtility.IsNullOrEmpty(users))
                this._users.AddRange(users.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

            if (!StringUtility.IsNullOrEmpty(securityGroups))
                this._securityGroups.AddRange(securityGroups.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

            if (!StringUtility.IsNullOrEmpty(spGroups))
                this._spGroups.AddRange(spGroups.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
        }

        public SecurityEntity(string accounts)
            : this()
        {
            string[] text1 = accounts.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            if (text1.Length == 0)
                return;

            this._users.AddRange(text1[0].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

            if (text1.Length > 1)
            {
                this._securityGroups.AddRange(text1[1].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

                if (text1.Length > 2)
                    this._spGroups.AddRange(text1[2].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
            }
        }

        #endregion

        #region Cast Operator

        public static implicit operator SecurityEntity(string s)
        {
            return new SecurityEntity(s);
        }

        #endregion

        #region Properties

        public StringCollection Users
        {
            get { return this._users; }
        }

        public StringCollection SecurityGroups
        {
            get { return this._securityGroups; }
        }

        public StringCollection SharePointGroups
        {
            get { return this._spGroups; }
        }

        public bool IsEmpty
        {
            get { return this.SecurityGroups.Count == 0 && this.SharePointGroups.Count == 0 && this.Users.Count == 0; }
        }

        #endregion

        #region Methods

        public void Add(PrincipalType type, string account)
        {
            switch (type)
            {
                case PrincipalType.User:
                    this.Users.Add(account);
                    break;
                case PrincipalType.SecurityGroup:
                    this.SecurityGroups.Add(account);
                    break;
                case PrincipalType.SharePointGroup:
                    this.SharePointGroups.Add(account);
                    break;
            }
        }

        public virtual string ToString(string separator)
        {
            string result = String.Empty;

            if (this.Users.Count != 0)
            {
                result = this.Users[0];

                for (int i = 1; i < this.Users.Count; i++)
                    result = result + "," + this.Users[i];
            }
            result += separator;
            if (this.SecurityGroups.Count != 0)
            {
                result += this.SecurityGroups[0];
                for (int i = 1; i < this.SecurityGroups.Count; i++)
                    result = result + "," + this.SecurityGroups[i];
            }
            result += separator;
            if (this.SharePointGroups.Count != 0)
            {
                result += this.SharePointGroups[0];
                for (int i = 1; i < this.SharePointGroups.Count; i++)
                    result = result + "," + this.SharePointGroups[i];
            }
            return result;
        }

        public override string ToString()
        {
            return this.ToString(";");
        }

        internal string AllNames()
        {
            string result = String.Empty;

            if (this.Users.Count != 0)
            {
                result = this.Users[0];

                for (int i = 1; i < this.Users.Count; i++)
                    result = result + "," + this.Users[i];
            }
            if (this.SecurityGroups.Count != 0)
            {
                result += (String.IsNullOrEmpty(result) ? "" : ",") + this.SecurityGroups[0];
                for (int i = 1; i < this.SecurityGroups.Count; i++)
                    result = result + "," + this.SecurityGroups[i];
            }            
            if (this.SharePointGroups.Count != 0)
            {
                result += (String.IsNullOrEmpty(result) ? "" : ",") + this.SharePointGroups[0];
                for (int i = 1; i < this.SharePointGroups.Count; i++)
                    result = result + "," + this.SharePointGroups[i];
            }
            return result;
        }

        public bool CheckCurrentUser(SPWeb web)
        {
            SPUser user = web.CurrentUser;

            if (web == null)
                throw new ArgumentNullException("web");

            if (this.IsEmpty)
                return true;
            
            foreach (string account in this.Users)
            {
                if (user.LoginName.Equals(account, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }

            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            foreach (string securityGroup in this.SecurityGroups)
                if (principal.IsInRole(securityGroup))
                    return true;

            SPGroup group;
            foreach (string s in this.SharePointGroups)
            {
                try { group = web.Groups[s.Trim()]; }
                catch { group = null; }

                if (group != null)
                    if (web.IsCurrentUserMemberOfGroup(group.ID))
                        return true;
            }

            return false;
        }

        #endregion
    }

    #region PrincipalType enum

    public enum PrincipalType
    {
        User = 0,
        SecurityGroup = 1,
        SharePointGroup = 2
    }

    #endregion
}
